/*
 * @(#)WorkflowProgressListener.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.workflow.core;

import java.sql.Connection;
import java.util.Date;
import java.util.List;

import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;
import org.quartz.impl.calendar.BaseCalendar;
import org.quartz.spi.TriggerFiredBundle;

import com.dcivision.framework.ApplicationException;
import com.dcivision.framework.GlobalConstant;
import com.dcivision.framework.SchedulerFactory;
import com.dcivision.framework.SystemParameterConstant;
import com.dcivision.framework.SystemParameterFactory;
import com.dcivision.framework.TextUtility;
import com.dcivision.framework.Utility;
import com.dcivision.framework.dao.AbstractDAObject;
import com.dcivision.workflow.bean.WorkflowProgress;
import com.dcivision.workflow.bean.WorkflowStep;
import com.dcivision.workflow.bean.WorkflowStepParameterValue;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;
import com.dcivision.workflow.dao.WorkflowStepParameterValueDAObject;
/**
 * WorkflowProgressListener.java
 * 
 * This class is responsible for workflow automatic task processor.
 * 
 * @author Rollo Chan
 * @company DCIVision Limited
 * @creation date 24/10/2003
 * @version $Revision: 1.17 $
 */
public class WorkflowProgressListener {
  
  public static final String REVISION = "$Revision: 1.17 $";
  
  protected org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(this.getClass().getName());
  
  public WorkflowProgressListener() {
  }
  
  /**
   * Performs the action after a workflow progress has been created
   * 
   * @param eventObject The event object
   */
  //public void actionPerformed(ProgressActionEvent eventObject) {
  public void actionPerformed(ProgressActionEvent eventObject,Connection dbConn) {
    log.info("*** WorkflowProgressListener.actionPerformed:" + (String) eventObject.getCommand());
    if (WorkflowProgressDAObject.POST_CREATE_WORKFLOW_PROGRES.equals(eventObject.getCommand())) {
      performWkStepAutoAction(eventObject,dbConn);
    }
  }
  
  //private void performWkStepAutoAction(ProgressActionEvent event) {
  private void performWkStepAutoAction(ProgressActionEvent event,Connection dbConn) {
    log.info("*** WorkflowProgressListener.performWkStepAutoAction:");
    if (event.getParams()[0] instanceof WorkflowProgress) {
      WorkflowProgress progress = (WorkflowProgress) event.getParams()[0];
      scheduleAutomaticTask(progress, event.getSource(),dbConn);
    }
  }
  
  private synchronized void scheduleAutomaticTask(WorkflowProgress wprogress, Object eventSource,Connection dbConn){
    Scheduler sched = null;
    SimpleTrigger trigger = null;
    try {
      log.info("-=-=-=-=-=-=-START scheduleAutomaticTask-=-=-=-=-=-=-=-=");
      
      sched = SchedulerFactory.getScheduler();
      JobDataMap dataMap = new JobDataMap();
      dataMap.put("workflowProgress", wprogress);
      dataMap.put("userID", ((AbstractDAObject)eventSource).getSessionContainer().getUserRecordID());
      JobDetail job = new JobDetail(GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+wprogress.getID(), GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+"GROUP", AutomaticTaskHandler.class);
      job.setJobDataMap(dataMap);
      
      //calculate the schedule date
      Date scheduleDate = null;
      //add by greatwall for eip112
      int delay = getDelay(wprogress, eventSource, dbConn);
      //end
      if(delay >= 0){
      scheduleDate = new Date(Utility.getCurrentTimestamp().getTime() + (delay + (wprogress.getID().intValue())%10 ) * 1000L);
      
      if (scheduleDate!=null){
        log.info("schedule date: "+ scheduleDate.toString());
        
        // This trigger will repeat every repeat interval time after the start time for every until it is killed.
        trigger = new SimpleTrigger(
                GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO + wprogress.getID(), // Trigger name.
                GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO + "GROUP", // Trigger group.
                GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO + wprogress.getID(), // Job name.
                GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO + "GROUP", // Job group.
                scheduleDate, // Start time.
                null, // End time, forever.
                SimpleTrigger.REPEAT_INDEFINITELY, // Repeat count, infinite.
                delay >= 0 ? delay : 10 * 1000L // Repeat interval time.
        );
        trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT);
        job.addJobListener(AutomaticTaskHandler.AUTOMATIC_TASK_LISTENER_EKY);
        
        /*
        trigger = new SimpleTrigger(GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+wprogress.getID(), GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+"GROUP", GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+wprogress.getID(), GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+"GROUP", scheduleDate, null, 0, 0);
        trigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
        */
        log.info("trigger created");
        
        log.info(job.getFullName() + " will run at: " + trigger.getNextFireTime() + " & repeat: " + trigger.getRepeatCount() + "/" + trigger.getRepeatInterval());
        sched.scheduleJob(job, trigger);
        log.info("Add schedule for wprogressID="+wprogress.getID()+" finished!");
        }
      }else{
        log.info("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
        log.info("Trigger the automatic task IMMEDIATELY !!!");
        log.info("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");        
        AutomaticTaskHandler automaticTaskHandler = new AutomaticTaskHandler();
        job.getJobDataMap().put("connection",dbConn);
        scheduleDate = new Date(Utility.getCurrentTimestamp().getTime());
        trigger = new SimpleTrigger(GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+wprogress.getID(), GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+"GROUP", GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+wprogress.getID(), GlobalConstant.JOB_PREFIX_WORKFLOW_AUTO+"GROUP", scheduleDate, null, 0, 0);
        trigger.setJobDataMap(job.getJobDataMap());
        // context = new JobExecutionContext(sched,trigger,new org.quartz.impl.calendar.BaseCalendar(),job,new AutomaticTaskHandler(),true);
        TriggerFiredBundle triggerFiredBundle=new TriggerFiredBundle(job,trigger,new BaseCalendar(),true,new Date(),new Date(),null,null);
        JobExecutionContext context =new JobExecutionContext(sched,triggerFiredBundle,automaticTaskHandler);
        automaticTaskHandler.execute(context);
      }
    } catch (Exception e) {
      log.error("scheduleAutomaticTask error", e);
    } finally {
      log.info("-=-=-=-=-=-=-END scheduleAutomaticTask-=-=-=-=-=-=-=-=");
    }
  }

  /**
   * add by greatwall for eip112
   * @param wprogress
   * @param eventSource
   * @param dbConn
   * @return
   * @throws ApplicationException
   */
  private int getDelay(WorkflowProgress wprogress, Object eventSource, Connection dbConn) throws ApplicationException {
    int delay = TextUtility.parseInteger(SystemParameterFactory
        .getSystemParameter(SystemParameterConstant.WORKFLOW_AUTOMATIC_TASK_DELAY_TIME));
    String autoTaskType = "";
    WorkflowStep wfs = wprogress.getWorkflowStepSource();
    if (wfs.getActionType().equals(WorkflowStep.ACTION_TYPE_SYSTEM_AUTO)) {
      WorkflowStepParameterValueDAObject wfStepParameterDAO = new WorkflowStepParameterValueDAObject(
          ((AbstractDAObject) eventSource).getSessionContainer(), dbConn);
      List stepParamValueList = wfStepParameterDAO.getListByStepID(wfs.getID());
      WorkflowStepParameterValue tmpWorkflowStepParameterValue = null;
      for (int i = 0; i < stepParamValueList.size(); i++) {
        tmpWorkflowStepParameterValue = (WorkflowStepParameterValue) stepParamValueList.get(i);
        if (WorkflowRetrievalManager.PARAMVALUE_AUTOTASK.equals(tmpWorkflowStepParameterValue.getParameterType())) {
          delay = TextUtility.parseInteger(tmpWorkflowStepParameterValue.getParameterName());
          autoTaskType = tmpWorkflowStepParameterValue.getParameterValue();
        }
      }
      /*if(autoTaskType.equals("Sync"))
      {
        //delay = -1;
        //for the auto task need delay some times.
        delay = 2;
      }else{*/
        if(delay<=0){
          delay=TextUtility.parseInteger(SystemParameterFactory
              .getSystemParameter(SystemParameterConstant.WORKFLOW_AUTOMATIC_TASK_DELAY_TIME));
        }            
      //}
    }else
    {
      delay=TextUtility.parseInteger(SystemParameterFactory
          .getSystemParameter(SystemParameterConstant.WORKFLOW_AUTOMATIC_TASK_DELAY_TIME));
    }
    return delay;
  }
}